﻿using Devil;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

namespace GameToolkit.UI
{
    /// <summary>
    /// panel 实现已控制遮罩透明度
    /// </summary>
    public interface IPanelMaskTransparency
    {
        float Transparency { get; }
    }

    /// <summary>
    /// panel 实现以激活后处理
    /// </summary>
    public interface IPanelMaskWithVolumeProfile
    {
    }

    [RequireComponent(typeof(Canvas)), DisallowMultipleComponent]
    public class BackgroundPanelMask : MonoBehaviour
    {
        [SerializeField]
        Graphic m_MaskObj;

#if SRP_URP
        [SerializeField]
        Volume m_MaskVol;
#endif

        [SerializeField, Range(0, 1f)]
        float m_MaskOpaque = 0.7f;

        [SerializeField, Range(0, 1f)]
        float m_CrossOpaqueDuration = 0.2f;

        Canvas mCanvas;
        Canvas GetCanvas()
        {
            if (mCanvas == null)
                mCanvas = GetComponent<Canvas>();
            return mCanvas;
        }

        PanelManager mgr;
        bool mFinishCross;
        bool mFinalActive;

        float mCrossSpeed;
        float mCrossProgress;

        float mStartOpaque;
        float mFinalOpaque;

        float mStartWeight;
        float mFinalWeight;

        private void Awake()
        {
            mgr = GetComponentInParent<PanelManager>();
        }

        private void OnEnable()
        {
            mCrossSpeed = m_CrossOpaqueDuration > 0 ? (1f / m_CrossOpaqueDuration) : 100f;
            if (mgr == null)
                mgr = PanelManager.Instance;
            if(mgr != null)
            {
                mgr.OnForegroundPanelChanged += OnForeGroundChanged;
            }
        }

        private void OnDisable()
        {
            if(mgr != null)
            {
                mgr.OnForegroundPanelChanged -= OnForeGroundChanged;
            }
        }

        private void Update()
        {
            if (!mFinishCross)
            {
                mCrossProgress += Time.unscaledDeltaTime * mCrossSpeed;
                mFinishCross = mCrossProgress >= 1;
                var p = Mathf.Clamp01(mCrossProgress);
                var p2 = p * p;
                if (m_MaskObj != null)
                {
                    var col = m_MaskObj.color;
                    col.a = Mathf.Lerp(mStartOpaque, mFinalOpaque, p2);
                    m_MaskObj.color = col;
                    if (mFinishCross && !mFinalActive)
                        m_MaskObj.gameObject.SetActive(false);
                }
#if SRP_URP
                if(m_MaskVol != null)
                {
                    m_MaskVol.weight = Mathf.Lerp(mStartWeight, mFinalWeight, p);
                    if (mFinishCross && !mFinalActive)
                        m_MaskVol.gameObject.SetActive(false);
                }
#endif
            }
        }

        private void OnForeGroundChanged(Panel panel)
        {
            mFinishCross = false;
            mCrossProgress = 0;
            mFinalActive = panel != null;
            if (m_MaskObj != null)
            {
                mStartOpaque = m_MaskObj.color.a;
                if (mFinalActive)
                {
                    var transparency = panel is IPanelMaskTransparency trans ? Mathf.Clamp01(trans.Transparency) : 0;
                    mFinalOpaque = m_MaskOpaque * (1 - transparency);
                    m_MaskObj.gameObject.SetActive(true);
                }
                else
                {
                    mFinalOpaque = 0;
                }
            }
#if SRP_URP
            if (m_MaskVol != null)
            {
                mStartWeight = m_MaskVol.weight;
                if (mFinalActive)
                {
                    mFinalWeight = 0f;
                    var lst = CachedList<Panel>.GetList();
                    PanelManager.Instance.GetPanelStack(lst);
                    for (int i = 0; i < lst.Count; i++)
                    {
                        if (lst[i] is IPanelMaskWithVolumeProfile)
                        {
                            mFinalWeight = 1f;
                            break;
                        }
                    }
                    CachedList<Panel>.Release(lst);
                    m_MaskVol.gameObject.SetActive(mFinalActive);
                }
                else
                {
                    mFinalWeight = 0;
                }
            }
#endif
            var canvas = GetCanvas();
            if(canvas != null && panel != null)
            {
                var pcanvas = panel.GetCanvas();
                canvas.sortingLayerID = pcanvas.sortingLayerID;
                canvas.sortingOrder = pcanvas.sortingOrder - 1;
                canvas.planeDistance = pcanvas.planeDistance;
            }
        }

#if UNITY_EDITOR
        private void OnValidate()
        {
            mCrossSpeed = m_CrossOpaqueDuration > 0 ? (1f / m_CrossOpaqueDuration) : 100f;
        }
#endif
    }
}
